#include "cvcalibrategui.h"

using namespace bottracker;

CvCalibrateGUI::CvCalibrateGUI( BaseObjectType* base_object,
                                const Glib::RefPtr<Gnome::Glade::Xml>& refXml) : Gtk::Window(base_object)
{

    refXml->get_widget( "buttonGrab", pm_ButtonGrab );              ///< Podpięcie widgetów do zmiennych z aplikacji
    refXml->get_widget( "buttonCalibrate", pm_ButtonCalibrate );
    refXml->get_widget( "buttonClose", pm_ButtonClose );
	refXml->get_widget( "buttonSave", pm_ButtonSave );
    refXml->get_widget( "imageCalibLive", pm_ImageCalibLive );
    refXml->get_widget( "labelGrabbed", pm_LabelGrabbed );
    refXml->get_widget( "spinbuttonSize", pm_SpinbuttonSize );
    refXml->get_widget( "spinbuttonCornersX", pm_SpinbuttonCornersX );
    refXml->get_widget( "spinbuttonCornersY", pm_SpinbuttonCornersY );
    refXml->get_widget( "entryMat11", pm_EntryMat11 );
    refXml->get_widget( "entryMat12", pm_EntryMat12 );
    refXml->get_widget( "entryMat13", pm_EntryMat13 );
    refXml->get_widget( "entryMat21", pm_EntryMat21 );
    refXml->get_widget( "entryMat22", pm_EntryMat22 );
    refXml->get_widget( "entryMat23", pm_EntryMat23 );
    refXml->get_widget( "entryMat31", pm_EntryMat31 );
    refXml->get_widget( "entryMat32", pm_EntryMat32 );
    refXml->get_widget( "entryMat33", pm_EntryMat33 );

	pm_ButtonGrab->signal_clicked().connect(sigc::mem_fun(*this, &CvCalibrateGUI::button_grab_frame_clicked)); ///< Podłączenie sygnałów do funkcji obsługujących
	pm_ButtonClose->signal_clicked().connect(sigc::mem_fun(*this, &CvCalibrateGUI::button_close_clicked));
    pm_ButtonSave->signal_clicked().connect(sigc::mem_fun(*this, &CvCalibrateGUI::button_save_clicked));
    pm_ButtonCalibrate->signal_clicked().connect(sigc::mem_fun(*this, &CvCalibrateGUI::button_calibrate_clicked));
    pm_SpinbuttonCornersX->signal_value_changed().connect(sigc::mem_fun(*this, &CvCalibrateGUI::spinbutton_value_changed));
    pm_SpinbuttonCornersY->signal_value_changed().connect(sigc::mem_fun(*this, &CvCalibrateGUI::spinbutton_value_changed));

	pm_ButtonCalibrate->set_sensitive(false);                       ///< Wyłączenie pewnych widgetów
	pm_ButtonGrab->set_sensitive(false);
	pm_ButtonSave->set_sensitive(false);

    pm_Cam = 0;

	pm_Capture = cvCaptureFromCAM(-1);                              ///< Inicjalizacja pobierania obrazu	if(pm_Capture)
	{
		cvSetCaptureProperty( pm_Capture, CV_CAP_PROP_FRAME_WIDTH, WIDTH );
		cvSetCaptureProperty( pm_Capture, CV_CAP_PROP_FRAME_HEIGHT, HEIGHT );
		cvWaitKey(DELAY);
	}
}

CvCalibrateGUI::~CvCalibrateGUI()
{
    delete pm_Cam;
    delete pm_CornersFound;
	delete pm_CalibWin;
}

void CvCalibrateGUI::button_close_clicked()
{
    hide();
}
bool CvCalibrateGUI::on_timer()
{
    pm_Frame = cvQueryFrame( pm_Capture );
    IplImage* tmp = cvCloneImage( pm_Frame );
    int success = cvFindChessboardCorners( tmp,
                                           pm_Cam->pm_BoardSize,
                                           pm_CornersFound,
                                           &pm_CornersCount,
                                           0 );
    cvDrawChessboardCorners( tmp,
                             pm_Cam->pm_BoardSize,
                             pm_CornersFound,
                             pm_CornersCount,
                             success );


    Glib::RefPtr<Gdk::Pixbuf> pixbuf = Gdk::Pixbuf::create_from_data( (guint8*)tmp->imageData,
                                                                      Gdk::COLORSPACE_RGB,
                                                                      false,
                                                                      pm_Frame->depth,
                                                                      pm_Frame->width,
                                                                      pm_Frame->height,
                                                                      pm_Frame->width*3);
    pm_ImageCalibLive->set(pixbuf);
    cvWaitKey(2);
    return true;
}

void CvCalibrateGUI::button_save_clicked()
{
    Gtk::FileChooserDialog dialog("Please choose a filename to save data", Gtk::FILE_CHOOSER_ACTION_SAVE);
    dialog.set_transient_for(*this);

    dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
    dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);

    Gtk::FileFilter filter_xml;
    filter_xml.set_name("XML files");
    filter_xml.add_mime_type("text/xml");
    dialog.add_filter(filter_xml);

    int result = dialog.run();
    switch(result)
    {
        case(Gtk::RESPONSE_OK):
        {
            std::string filename = dialog.get_filename();
            size_t pos = filename.find( ".xml", 0 );
            if( int(pos) == -1 )
                filename+=".xml";
            pm_Cam->save_data(filename.c_str());
            break;
        }
        case(Gtk::RESPONSE_CANCEL):
        {
            break;
        }
        default:
            break;
    }
}

void CvCalibrateGUI::button_grab_frame_clicked()
{
    Glib::Mutex::Lock lock(pm_Mutex);
    pm_Cam->get_frame(pm_Frame);
    pm_LabelGrabbed->set_text(int2ustring(pm_Cam->pm_Grabbed));
    pm_ButtonCalibrate->set_sensitive(true);
}
void CvCalibrateGUI::spinbutton_value_changed()
{
    if(pm_Capture)
        pm_ButtonGrab->set_sensitive(true);
    if( !pm_Cam)
        pm_Cam = new CvCamera( cvSize(WIDTH,HEIGHT),
                               cvSize(pm_SpinbuttonCornersX->get_value_as_int(),
                                      pm_SpinbuttonCornersY->get_value_as_int()) );
    else
    {
        delete pm_Cam;
        pm_Cam = new CvCamera( cvSize(WIDTH,HEIGHT),
                               cvSize(pm_SpinbuttonCornersX->get_value_as_int(),
                                      pm_SpinbuttonCornersY->get_value_as_int()) );
        pm_Cam->pm_Grabbed = 0;
        pm_LabelGrabbed->set_text(int2ustring(pm_Cam->pm_Grabbed));
    }
    pm_CornersFound = new CvPoint2D32f[pm_SpinbuttonCornersX->get_value_as_int()*pm_SpinbuttonCornersY->get_value_as_int()];
    Glib::signal_timeout().connect( sigc::mem_fun(*this, &CvCalibrateGUI::on_timer), 20 );
}

void CvCalibrateGUI::button_calibrate_clicked()
{
    pm_Cam->calibrate( pm_SpinbuttonSize->get_value_as_int() );
    pm_ButtonSave->set_sensitive(true);
}
